Django documentation

3. Giving models custom methods and custom module-level functions

Any method you add to a model will be available to instances.

Custom methods have the same namespace as if the model class were defined in the dynamically-generated module. That is, methods can access get_list(), get_object(), AddManipulator, and all other module-level objects.

Also, custom methods have access to a few commonly-used objects for convenience:

  • The datetime module from Python's standard library.
  • The db object from django.core.db. This represents the database connection, so you can do custom queries via a cursor object.

If your model method starts with "_module_", it'll be a module-level function instead of a method. Otherwise, custom module-level functions have the same namespace as custom methods.

Model source code

from django.core import meta

class Article(meta.Model):
    headline = meta.CharField(maxlength=100)
    pub_date = meta.DateField()

    def __repr__(self):
        return self.headline

    def was_published_today(self):
        return self.pub_date == datetime.date.today()

    def get_articles_from_same_day_1(self):
        return get_list(id__ne=self.id, pub_date__exact=self.pub_date)

    def get_articles_from_same_day_2(self):
        """
        Verbose version of get_articles_from_same_day_1, which does a custom
        database query for the sake of demonstration.
        """
        cursor = db.cursor()
        cursor.execute("""
            SELECT id, headline, pub_date
            FROM custom_methods_articles
            WHERE pub_date = %s
                AND id != %s""", [str(self.pub_date), self.id])
        # The asterisk in "Article(*row)" tells Python to expand the list into
        # positional arguments to Article().
        return [Article(*row) for row in cursor.fetchall()]

API reference

Article objects have the following methods:

  • delete()
  • get_articles_from_same_day_1()
  • get_articles_from_same_day_2()
  • get_next_by_pub_date()
  • get_previous_by_pub_date()
  • save()
  • was_published_today()

Sample API usage

This sample code assumes the above model has been saved in a file examplemodel.py.

>>> from django.models.examplemodel import articles

# Create a couple of Articles.
>>> from datetime import date
>>> a = articles.Article(id=None, headline='Area man programs in Python', pub_date=date(2005, 7, 27))
>>> a.save()
>>> b = articles.Article(id=None, headline='Beatles reunite', pub_date=date(2005, 7, 27))
>>> b.save()

# Test the custom methods.
>>> a.was_published_today()
False
>>> a.get_articles_from_same_day_1()
[Beatles reunite]
>>> a.get_articles_from_same_day_2()
[Beatles reunite]
>>> b.get_articles_from_same_day_1()
[Area man programs in Python]
>>> b.get_articles_from_same_day_2()
[Area man programs in Python]

Comments

Randy July 30, 2005 at 1:10 p.m.

def get_articles_from_same_day_1(self):
..return get_list(id__ne=self.id, pub_date__exact=self.pub_date)

I have a question about this syntax. It has the form field__condition, where field is some field within the data model, and condition is the matching condition.

The keyword creation is the key to how you wish to query.

Why not just pass in a function, that returns true/false, and determines if the record is valid. Lambda functions would work nicely in this situation.

For example:

def get_articles_from_same_day_3(self):
..filter = lambda x: x.id != self.id and x.pub_date == self.pub_date
..return get_list(filter)

Allowing arbitrary functions gives the programmer flexibility to provide complex filtering and querying without having to resort to SQL statements.

Adrian Holovaty July 30, 2005 at 1:57 p.m.

Randy: Because doing a "SELECT *" and filtering the results in Python is extremely inefficient.

rdk July 30, 2005 at 5:09 p.m.

"""
return get_list(id__ne=self.id, pub_date__exact=self.pub_date)
"""
I don't personally like another syntax included (__exact, __ne), when we already deal with Python and SQL syntax.

What about using this?

"""
return get_list("id!=self.id, pub_date==self.pub_date")
"""
it is shorter and more explaining, (while you can still translate string into the SQL syntax)

Adrian Holovaty August 1, 2005 at 1:54 p.m.

rdk: Feel free to use another object-relational mapper. You're not tied to using Django's.

Simon Willison September 16, 2005 at 8:39 a.m.

I missed the bit about _module_ methods being added to the module as opposed to the instances. Can we emphasize that point a bit? Maybe give it it's own header on the page and add an example.

Sarah November 2, 2005 at 3:06 p.m.

Does the change in namespace still allow access to modules generated for other objects?

I would like to be able to use the Django database API within an object method to retreive custom relationships. (At the instance level, _module_ already allows access to other lookup APIs)

Adrian Holovaty November 3, 2005 at 9:47 p.m.

Sarah: Other model modules aren't immediately available in the model module namespaces, but you can feel free to import them within the functions.

Post a comment

Note: Please only use the comments for questions/critcisms/suggestions on the docs; if you experience errors please file a ticket, ask in the IRC channel, or post to the django-users list. Comments will be periodically reviewed, integrated into the documentation proper, and removed.

Your name:

Comment: